package monster.comm.util;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StringReader;
import java.sql.ResultSetMetaData;
import java.sql.Types;
import java.util.ArrayList;
import java.util.HashMap;

import sun.jdbc.rowset.CachedRowSet;
import monster.comm.database.DBManager;
import monster.comm.dialect.Dialect;
import monster.comm.log.ILog;
import monster.comm.log.LogService;


/**
 * 
* 创建信息=============
* 类名: monster.comm.util.CreateMybatisHelp
* 类作用描述: mybatis自动生成帮助类，主要生成po,dao,mybatis配置文件
* 创建人： wanghong 
* 创建时间： 2013-1-9 上午11:21:57
* 修改信息1=============
* 修改类型:     //1.修改bug 2.业务变化修改
* 修改描述: 
* 修改人：  
* 修改时间：
 */
public class CreateMybatisHelp {
   private static ILog log = LogService.getLog(CreateMybatisHelp.class);
   private CodeHelpVO codeHelpVO;
   private ArrayList<String> tbl_list;
   private HashMap<String,TableVO> tbl_map;
   
   public CreateMybatisHelp(CodeHelpVO codeHelpVO,ArrayList<String> tbl_list,HashMap<String,TableVO> tbl_map){
	this.codeHelpVO=codeHelpVO;
	this.tbl_list=tbl_list;
	this.tbl_map=tbl_map;
  }
	
	/**
	 * 创建dao daoImp java 文件
	 * @throws Exception
	 */
	 public void createDAOFile() throws Exception{
		    File temp = new File(codeHelpVO.getDao_service_path());
		    if(!temp.exists()){
		      temp.mkdir();
		    }		     
		    String tbName="";
		     log.info("/*********创建java代码开始***********/");
		     for(int i=0;i<tbl_list.size();i++){
		       tbName=tbl_list.get(i);
		       createDaoIterfaceFile(tbName,tbl_map.get(tbName).getKeyColumn());
		       //createDaoImpFile(tbName);
		     }
		     log.info("/*********创建java代码结束***********/");
		  }
	 
	  /**
	   * 创建表DAO对应的接口文件
	   * @param tbName String表名
	   * @param pk String表名主键名
	   * @throws Exception
	   */
	  private void createDaoIterfaceFile(String tbName,String pk) throws Exception{

	    String fileContext=getDAOInterfaceContext(tbName,pk);
	    String cname=tbName.substring(0,1).toUpperCase()+tbName.substring(1)+"DAO";//文件名
	    String daoPath=codeHelpVO.getDao_service_path();//文件路径
	    if(!daoPath.substring(daoPath.length()-1,daoPath.length()).equals("/")){//如果没有带"/",则加上
	    	daoPath+="/";
	    }
	   
	      
	     File file = new File(daoPath + cname + ".java");
	     Tool.createUtfFile(daoPath + cname + ".java", fileContext);
	  }
	  
	  /**
	   * 创建表DAOImp对应的文件
	   * @param tbName String表名
	   * @throws Exception
	   */
	  private void createDaoImpFile(String tbName) throws Exception{

	    String fileContext=this.getDAOImpContext(tbName);
	    String cname=tbName.substring(0,1).toUpperCase()+tbName.substring(1)+"DAOImp";
	    
	      String daoPath=codeHelpVO.getDao_imp_path();//文件路径
		    if(!daoPath.substring(daoPath.length()-1,daoPath.length()).equals("/")){//如果没有带"/",则加上
		    	daoPath+="/";
		    }
		    String fileName=daoPath+ cname + ".java";
		    Tool.createUtfFile(fileName, fileContext);
	  }

	
	/**
	   * 生成DAO 接口java文件
	   * @param tbName String
	   * @param pk String
	   * @throws Exception
	   * @return String
	   */
	  private String getDAOInterfaceContext(String tbName,String pk) throws Exception{
		 pk = pk.toLowerCase();//主键
	     String pojoName=tbName.substring(0,1).toUpperCase()+tbName.substring(1);//如Dept	     
	     String interfaceName=pojoName+"DAO";//eg: DeptDAO
	     StringBuilder sb=new StringBuilder(200);
	     sb.append("package "+codeHelpVO.getDao_service_packae().trim()+";\n");
	     sb.append("import java.util.List;\n");
	     sb.append("import "+codeHelpVO.getPo_package()+"."+pojoName+";\n\n");
	     sb.append("public interface "+interfaceName+" {\n\n");	  
	     sb.append("\t /**\n");
	     sb.append("\t*@Description: 根据主键返回"+pojoName+"\n");
	     sb.append("\t*@param "+pk+"\n");
	     sb.append("\t*@return "+pojoName+"\n");
	     sb.append("\t*/\n");
	     sb.append("\t public "+pojoName+" get"+pojoName+"ByID(String  "+pk+");\n");
	     sb.append("\t /**\n");
	     sb.append("\t*@Description: 根据bean返回List，如果bean中的属性不为null则作为查询条件\n");
	     sb.append("\t*@param "+pojoName+"\n");
	     sb.append("\t*@return List<"+pojoName+">\n");
	     sb.append("\t*/\n");
	     sb.append("\t public List<"+pojoName+"> get"+pojoName+"ByParams("+pojoName+" "+tbName+");\n");	     
	     sb.append("\t /**\n");
	     sb.append("\t*@Description: 新增一条记录\n");
	     sb.append("\t*@param "+pojoName+"\n");
	     sb.append("\t*@return void\n");
	     sb.append("\t*/\n");
	     sb.append("\t public void insert"+pojoName+"("+pojoName+" "+tbName+");\n");	     
	     sb.append("\t /**\n");
	     sb.append("\t*@Description: 根据主键更新记录\n");
	     sb.append("\t*@param "+pojoName+"\n");
	     sb.append("\t*@return void\n");
	     sb.append("\t*/\n");
	     sb.append("\t public void update"+pojoName+"("+pojoName+" "+tbName+");\n");	     	     
	     sb.append("\t /**\n");
	     sb.append("\t*@Description: 根据主键删除记录\n");
	     sb.append("\t*@param  "+pk+"\n");
	     sb.append("\t*@return void\n");
	     sb.append("\t*/\n");
	     sb.append("\t public void delete"+pojoName+"ByID(String  "+pk+");\n");
	     sb.append("\t /**\n");
	     sb.append("\t*@Description: 根据主键删除多条记录\n");
	     sb.append("\t*@param  "+pk+"s\n");
	     sb.append("\t*@return void\n");
	     sb.append("\t*/\n");
	     sb.append("\t public void delete"+pojoName+"ByIDs(List<String>  "+pk+"s);\n");
	     sb.append("}\n");
         
	     return sb.toString();
	  }

	  /**
	   * 得到DAO的实现类
	   * @param tbName String
	   * @throws Exception
	   * @return String
	   */
	  private String getDAOImpContext(String tbName) throws Exception{
	    String pojoName=tbName.substring(0,1).toUpperCase()+tbName.substring(1);//如Dept
	     String interfaceName=pojoName+"DAO";//eg: DeptDAO
	     StringBuffer sb=new StringBuffer();


	     return sb.toString();

	  }
	  
	  //=================================创建po=================================
	 /**
	  * 创建po对象
	  */
	  public void createPO() throws Exception{
		File temp = new File(codeHelpVO.getPo_path());
		if (!temp.exists()) {
			temp.mkdir();
		}
		String poPath = codeHelpVO.getPo_path();// 文件路径
		if (!poPath.substring(poPath.length() - 1, poPath.length()).equals("/")) {// 如果没有带"/",则加上
			poPath += "/";
		}
		try {
			for (int i = 0; i < tbl_list.size(); i++) {
				String cname = (String) tbl_list.get(i);

				cname = cname.substring(0, 1).toUpperCase()
						+ cname.substring(1);
				StringBuilder sb = new StringBuilder();
				sb.append("package " + codeHelpVO.getPo_package() + ";\n");
				sb.append("public class " + cname + "{\n");
				sb.append(getPoContent(cname));
				sb.append("}");

				String filePath = poPath + cname + ".java";
				Tool.createUtfFile(filePath, sb.toString());
			}

		} catch (Exception e) {
			System.out.println("创建po出现例外:" + e);
		}
	  }
	  /**
	   * 得到po的内容
	   * @param tblName
	   * @return
	   */
	  public String getPoContent(String tblName) throws Exception{
		  StringBuilder sb      = new StringBuilder();
		  StringBuilder sb_prop = new StringBuilder();
		  StringBuilder sb_get  = new StringBuilder();
		  StringBuilder sb_set  = new StringBuilder();
		  String sql="select * from "+tblName+" where 1=-1";
		  DBManager db = new DBManager();
		  CachedRowSet rs=db.getRowSet(sql);
		  ResultSetMetaData rm=rs.getMetaData();
		  rs  = db.getRowSet(getCommentSQL(tblName));
		  HashMap<String, String> commentsMap = new HashMap<String, String>();
		  while(rs.next()){
			  commentsMap.put(rs.getString(1).toLowerCase(), rs.getString(2));
		  }
		  int len=rm.getColumnCount();
		  for(int i=1;i<=len;i++){			
			  String dataType=rm.getColumnTypeName(i).toLowerCase();
			  int scale =rm.getScale(i);
			  String filedName=rm.getColumnName(i).toLowerCase();			  
			  sb_prop.append(getProp(filedName,dataType,scale,Tool.isNull(commentsMap.get(filedName))));//得到属性
			  sb_get.append(getHelp(filedName,dataType,scale));//get
			  sb_set.append(SetHelp(filedName,dataType,scale));//set
	     }
		  sb.append(sb_prop);
		  sb.append(sb_get);
		  sb.append(sb_set);
		  return sb.toString();
	  }
	  
      /**
       * 得到属性
       */
	  public String getProp(String fieldName,String dataType,int scal,String comment){
//	    String v="";
//	    v = "private "+getDBTypeToJava(dataType,scal)+" " + fieldName + ";\n";
		String v = "private String " + fieldName + ";//"+comment+"\n";
	   return v;
	  }
	  /**
	   * 得到字段的set
	   * @param fieldName
	   * @param dataType
	   * @param scal
	   * @return
	   */
	  public String SetHelp(String fieldName,String dataType,int scal){
		    String v = "";
		    //v+="public void set" + getFirstMax(fieldName) + "("+getDBTypeToJava(dataType,scal) + " "+fieldName + "){\n";
		    v+="public void set" + getFirstMax(fieldName) + "(String "+fieldName + "){\n";
	        v+="\t\t this." + fieldName + "="+fieldName+";\n";
	        v+= "\t}\n";  
		      return v;
	  }
	  
	  /**
	   * 得到字段的get
	   * @param fieldName
	   * @param dataType
	   * @param scal
	   * @return
	   */
	  public String getHelp(String fieldName,String dataType,int scal){
		    String v = "";
		    //v+="public "+getDBTypeToJava(dataType,scal)+" get" + getFirstMax(fieldName) + "(){\n";
		    v+="public String get" + getFirstMax(fieldName) + "(){\n";
		    v += "\t  return " + fieldName + ";\n";
		    v += "}\n"; 
		    return v;
	  }
	  
	  
	  //=======================创建dao在spring的注册XML====================
	  /**
	   * 得到表的spring配置文件
	   * @param classPath String dao对应的包eg:demo.persistent.dao.imp
	   * @throws Exception
	   */
	  public String  createSpringDaoXml() throws Exception{
		  StringBuffer springDaoXml=new StringBuffer();
	   for(int i=0;i<tbl_list.size();i++){
	     String tb=(String)tbl_list.get(i);
	     tb=tb.trim();
	     tb = tb.substring(0,1).toLowerCase()+tb.substring(1);
	     String cname=tb.substring(0,1).toUpperCase()+tb.substring(1)+"DAO";//文件名
		 String daoPage=codeHelpVO.getDao_service_packae();//文件路径
	     springDaoXml.append("<bean id=\""+tb+"DAO\" class=\"org.mybatis.spring.mapper.MapperFactoryBean\">\r");
	     springDaoXml.append("<property name=\"mapperInterface\" value=\""+daoPage+"."+cname+"\"></property>\r");
	     springDaoXml.append("<property name=\"sqlSessionFactory\" ref=\"sqlSessionFactory\"></property>\r");
	     springDaoXml.append("</bean>\r");
	     
	     
	   }
	   return springDaoXml.toString();
	  }
	  //=======================创建po在spring的注册XML====================
	  /**
	   * 得到po的spring配置文件
	   * @param classPath String po对应的包eg:demo.persistent.po
	   * @throws Exception
	   */
	  public String  createSpringPOXml() throws Exception{
		  StringBuffer springPOXml=new StringBuffer();
	   for(int i=0;i<tbl_list.size();i++){
	     String tableName=(String)tbl_list.get(i);
	     String tb=tableName.trim();
	     tb = tb.substring(0,1).toLowerCase()+tb.substring(1);
	     String po = tableName.trim().substring(0, 1).toUpperCase()+tb.substring(1);
		 springPOXml.append("<bean id=\""+tb+"\" class=\""+codeHelpVO.getPo_package()+"."+po+"\">");
		 springPOXml.append("</bean>\n");
	     
	     
	   }
	   return springPOXml.toString();
	  }
	
	  
	  
	  //========================================================================
	  /**
	   * 得到表配置文件在mybatis公共文件中的引用
	   */
       public String createMybatisConfig(){
    	   StringBuilder cfg=new StringBuilder();
    	   for(int i=0;i<tbl_list.size();i++){
    	     String tb=tbl_list.get(i);
    	     tb=tb.trim();
    	     cfg.append("<mapper resource=\"" + codeHelpVO.getMybatiscfg_path() + "/" + tb +
    	     	"_mapper.xml\"/>\n");
    	   }
    	   return cfg.toString();
       }
       
       //============================创建hbm文件==========================
       /**
        * 创建所有Mybatis文件
        * @throws Exception
        */

       public void createAllMybatisFile() throws Exception {
         File temp = new File(codeHelpVO.getMybatis_path().trim());
         if(!temp.exists()){
           temp.mkdir();
         }
         log.info("********创建所有mybatis文件开始***********");
         String path=codeHelpVO.getMybatis_path();
         if(!path.substring(path.length()-1,path.length()).equals("/")){//如果没有带"/",则加上
        	 path+="/";
		    }
         for (int i = 0; i < tbl_list.size(); i++) {
           String cname = (String) tbl_list.get(i);
           String sb = createMybatisFile(cname);
           BufferedReader br = null;
           StringReader sr = null;
           PrintWriter pw=null;
           BufferedWriter bw = null;
           OutputStreamWriter osw=null;
           FileOutputStream  fw = null;           
           try{
	            sr = new StringReader(sb);
	            br = new BufferedReader(sr);           
	            File file = new File( path+ cname + "_mapper.xml");	            
	            fw =  new FileOutputStream(file);	            
	            osw = new OutputStreamWriter(fw, "utf-8");
	            bw = new BufferedWriter(osw);
	            pw = new PrintWriter(bw);
	           String s1 = "";
	           while ( (s1 = br.readLine()) != null) {
	             //注意这里也可以用bw.write(String)但不能换行
	             //用pw.write(String)不会换行
	             pw.println(s1);
	           }
           }finally{
        	   if(pw!=null)pw.close();
        	   if(bw!=null)bw.close();
        	   if(osw!=null)osw.close();
        	   if(fw!=null)fw.close();
        	   if(br!=null)br.close();	
        	   if(sr!=null)sr.close();
           }

         }
         log.info("********创建所有mybatis文件结束***********");
       }
       
       /**
       *
       * @param tbName 表的名称
       * @param classPath 类的路径
       * @throws Exception
       */
      public String createMybatisFile(String tbName) throws Exception {
        StringBuilder sb = new StringBuilder();
        sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
        sb.append("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \n");
        sb.append("\"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n");
        sb.append(
            "<mapper namespace=\""
            + codeHelpVO.getDao_service_packae()
            + "."
            + tbName.substring(0, 1).toUpperCase()
            + tbName.substring(1)
            + "DAO\" >\n");
         sb.append(getMybatisProperty(tbName));

        sb.append("</mapper>\n");
        return sb.toString();
      }
      /**
       * 得到mybatis的内容
       * @param tbName
       * @return
       * @throws Exception
       */
      public String getMybatisProperty(String tbName) throws Exception {
        StringBuilder sb = new StringBuilder();
        
         String sql="select * from "+tbName+" where 1=-1";
		  CachedRowSet rs=new DBManager().getRowSet(sql);
		  java.sql.ResultSetMetaData rm=rs.getMetaData();
		  int len=rm.getColumnCount();  
		  String keyColumn = tbl_map.get(tbName).getKeyColumn().toLowerCase();
		  boolean isGenerated = tbl_map.get(tbName).isGenerated();//是否自动增长
		  StringBuilder sb_column = new StringBuilder(30);
		  StringBuilder sb_value = new StringBuilder(80);
		  StringBuilder sb_set = new StringBuilder(80);
          for (int i = 1; i <= len; i++) {
            String fieldName = rm.getColumnName(i).toLowerCase();
            int    columnType = rm.getColumnType(i);
            if(fieldName.equals(keyColumn)){//主键
            	if(isGenerated){//排除子增长主键
            		
            	}else{
            		sb_column.append(fieldName);
            		sb_value.append("#{").append(fieldName).append(",jdbcType=").append(getJdbcType(columnType)).append("}");
            		if(i<len){
                		sb_column.append(",\n");
                		sb_value.append(",\n");
                	}
            	}
            }else{//其他字段
            	sb_column.append(fieldName);
        		sb_value.append("#{").append(fieldName).append(",jdbcType=").append(getJdbcType(columnType)).append("}");
        		sb_set.append("").append(fieldName).append("=#{").append(fieldName).append(",jdbcType=").append(getJdbcType(columnType)).append("}");
            	if(i<len){
            		sb_column.append(",\n");
            		sb_value.append(",\n");
            		sb_set.append(",\n");
            	}
            }
           
          }
          String pojoName=tbName.substring(0,1).toUpperCase()+tbName.substring(1);//如Dept
          String po =  codeHelpVO.getPo_package()
          + "."
          + tbName.substring(0, 1).toUpperCase()
          + tbName.substring(1);
          sb.append("\t<select id=\"get"+pojoName+"ByID\" parameterType=\"String\" resultType=\""+po+"\">\n");
          sb.append("\t\tselect * from "+tbName+" where "+keyColumn+"=#{"+keyColumn+"}\n");
          sb.append("\t</select>\n");
          sb.append("\t<!-- 返回List<po> 但返回类型resultType必须设置为po-->\n");
          sb.append("\t<select id=\"get"+pojoName+"ByParams\" parameterType=\""+po+"\" resultType=\""+po+"\">\n");
          sb.append("\t\tselect * from "+tbName+" \n");
          sb.append("\t\t<where>\n");
          sb.append("\t\t<!--添加条件-->\n");
          sb.append("\t\t</where>\n");
          sb.append("\t</select>\n");
          sb.append("<!-- 自动生成主键,必须配置 useGeneratedKeys=\"true\" keyProperty=\"主键\"-->\n");
          if(isGenerated){
        	  sb.append("\t<insert id=\"insert"+pojoName+"\" parameterType=\""+po+"\"   useGeneratedKeys=\"true\" keyProperty=\""+keyColumn+"\">\n");
          }else{
        	  sb.append("\t<insert id=\"insert"+pojoName+"\" parameterType=\""+po+"\"  >\n");
          }          
          sb.append("\t\tinsert into "+tbName+"("+sb_column+")\n");
          sb.append("\t\t\tvalues("+sb_value+")\n");
          sb.append("\t</insert>\n");
          sb.append("\t<update id=\"update"+pojoName+"\" parameterType=\""+po+"\"  >\n");
          sb.append("\t\t update "+tbName+"\n");          
          sb.append("\t\t<set>\n");
          sb.append("\t\t"+sb_set+"\n");         
          sb.append("\t\t</set>\n");
          sb.append("\t\twhere "+keyColumn+"=#{"+keyColumn+"}\n");
          sb.append("\t</update>\n");
          sb.append("<!--删除一条记录-->\n");
          sb.append("\t<delete id=\"delete"+pojoName+"ByID\" parameterType=\"String\"  >\n");
          sb.append("\t\t delete "+tbName+" where "+keyColumn+"=#{"+keyColumn+"}\n");
          sb.append("\t</delete>\n");
          sb.append("<!--删除多条记录-->\n");
          sb.append("\t<delete id=\"delete"+pojoName+"ByIDs\" >\n");
          sb.append("\t\t delete "+tbName+" where "+keyColumn+" in \n");
          sb.append("\t\t\t<foreach collection=\""+keyColumn+"s\" index=\"index\" item=\"item\" open=\"(\" separator=\",\" close=\")\">\n");
          sb.append("\t\t\t\t#{item}\n");
          sb.append("\t\t\t</foreach>\n");
          sb.append("\t</delete>\n");
          sb.append("");
        return sb.toString();
      }

	  /**
	   * 这里只归纳常见的类型String Long BigDemical
	   * @param dbType
	   * @return
	   */
	  private String getDBTypeToJava(String dbType,int scal){
		  String ret="String";
		  if(dbType.equals("number")  //orcale
			||	dbType.equals("bigint") ||	dbType.equals("decimal") ||	dbType.equals("float") ||	dbType.equals("int")  ||	dbType.equals("numeric")  
			||	dbType.equals("tinyint")  ||	dbType.equals("smallint")  //sql server 
		   ){
			  if(scal>0){
				  ret="java.math.BigDecimal";
			  }
			  else
				  ret="Long";
		  }
		  return ret;
	  }
	  
	  /**
	   * 第一个字母大写
	   * @param field
	   * @return
	   */
	  private String getFirstMax(String field){
			    return field.substring(0, 1).toUpperCase() + field.substring(1);

	  }
	  /**
	   * 获得jdbcType
	   * @param field
	   * @return
	   */
	  private String getJdbcType(int columnType){
		  String type="";
			   switch (columnType) {
			case Types.VARCHAR:
				type="VARCHAR";
				break;
			case Types.NVARCHAR:
				type="NVARCHAR";
				break;
			case Types.CHAR:
				type="CHAR";
				break;
			case Types.NCHAR:
				type="NCHAR";
				break;
			case Types.INTEGER:
				type="INTEGER";
				break;
			case Types.BIGINT:
				type="BIGINT";
				break;
			case Types.BIT:
				type="BIT";
				break;
			case Types.NUMERIC:
				type="NUMERIC";
				break;
			case Types.DECIMAL:
				type="DECIMAL";
				break;
			case Types.DOUBLE:
				type="DOUBLE";
				break;
			case Types.DATE:
				type="DATE";
				break;
			default:
				type="VARCHAR";
				break;
			}
        return type;
	  }
	  private String getCommentSQL(String tableName) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
		  Dialect dialect = (Dialect)Class.forName(SysConstant.dialectClass).newInstance();
		  return dialect.getCommentSQL(tableName);
	  }
	  

}


